package com.william.jdbcplus.core.dialect.ddl.util;

import com.william.jdbcplus.common.enums.DbType;
import com.william.jdbcplus.core.dialect.ddl.index.IIndex;
import com.william.jdbcplus.core.dialect.ddl.index.IndexFactory;
import com.william.jdbcplus.core.dialect.ddl.util.model.TableMeta;
import com.william.jdbcplus.core.meta.TableIndexInfo;
import com.william.jdbcplus.core.meta.TableInfo;
import com.william.jdbcplus.core.toolkit.StringUtil;
import com.william.jdbcplus.core.util.JdbcExecUtil;
import com.william.jdbcplus.core.util.datameta.TableMetaIndexInfo;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 索引处理
 *
 * @author niliwei
 */
public class IndexUtil {
    /**
     * 检查索引是否一致
     *
     * @param dbType    数据库类型
     * @param tableMeta 表信息
     * @return
     */
    public static List<String> check(DbType dbType, TableMeta tableMeta) {
        List<String> errList = new LinkedList<>();
        List<TableMetaIndexInfo> metaIndexInfos = tableMeta.getTableMeta().getIndexList();
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableIndexInfo> indexList = tableInfo.getIndexList();

        //处理库中索引数据
        Map<String, List<TableMetaIndexInfo>> indexMap = metaIndexInfos.stream().filter(e -> StringUtil.isNotBlank(e.getIndexName())).collect(Collectors.groupingBy(TableMetaIndexInfo::getIndexName));
        List<TableIndexInfo> metaList = new ArrayList<>();
        for (Map.Entry<String, List<TableMetaIndexInfo>> entry : indexMap.entrySet()) {
            List<TableMetaIndexInfo> valList = entry.getValue();
            Boolean nonUnique = valList.get(0).getNonUnique();
            TableIndexInfo info = new TableIndexInfo();
            info.setUnique(!nonUnique);
            info.setIndexName(valList.get(0).getIndexName());
            info.setColumns(valList.stream().map(e -> e.getColumnName().toLowerCase()).collect(Collectors.toList()));
            metaList.add(info);
        }

        for (TableIndexInfo indexInfo : indexList) {
            List<String> columns = indexInfo.getColumns().stream().map(e -> e.toLowerCase()).collect(Collectors.toList());
            TableIndexInfo exist = metaList.stream().filter(e -> e.getColumns().containsAll(columns) && columns.containsAll(e.getColumns())).findFirst().orElse(null);
            if (exist != null) {
                // 数据表中索引名已经存在, 则修改索引
                if (exist.isUnique() != indexInfo.isUnique()) {
                    errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中关联索引字段 " + columns.stream().collect(Collectors.joining(" ")) + " 索引类型不一致");
                }
            } else {
                // 数据表中索引名不存在，则新增索引
                errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中关联索引字段 " + columns.stream().collect(Collectors.joining(" ")) + " 不存在");
            }
        }

        return errList;
    }

    /**
     * 更新索引结构
     *
     * @param dbType    数据库类型
     * @param tableMeta 实体表结构信息
     * @param ds        数据源
     * @return
     */
    public static void update(DbType dbType, TableMeta tableMeta, DataSource ds) {
        List<TableMetaIndexInfo> metaIndexInfos = tableMeta.getTableMeta().getIndexList();
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableIndexInfo> indexList = tableInfo.getIndexList();

        //处理库中索引数据
        Map<String, List<TableMetaIndexInfo>> indexMap = metaIndexInfos.stream().filter(e -> StringUtil.isNotBlank(e.getIndexName())).collect(Collectors.groupingBy(TableMetaIndexInfo::getIndexName));
        List<TableIndexInfo> metaList = new ArrayList<>();
        for (Map.Entry<String, List<TableMetaIndexInfo>> entry : indexMap.entrySet()) {
            List<TableMetaIndexInfo> valList = entry.getValue();
            Boolean nonUnique = valList.get(0).getNonUnique();
            TableIndexInfo info = new TableIndexInfo();
            info.setUnique(!nonUnique);
            info.setIndexName(valList.get(0).getIndexName());
            info.setColumns(valList.stream().map(e -> e.getColumnName().toLowerCase()).collect(Collectors.toList()));
            metaList.add(info);
        }

        IIndex iIndex = IndexFactory.getInstance(dbType);
        for (TableIndexInfo indexInfo : indexList) {
            List<String> columns = indexInfo.getColumns().stream().map(e -> e.toLowerCase()).collect(Collectors.toList());
            TableIndexInfo dbIndex = metaList.stream().filter(e -> e.getColumns().containsAll(columns) && columns.containsAll(e.getColumns())).findFirst().orElse(null);
            if (dbIndex != null) {
                // 数据表中索引名已经存在, 则修改索引
                if (dbIndex.isUnique() != indexInfo.isUnique()) {
                    String sql = iIndex.modify(tableMeta.getClazz(), indexInfo, dbIndex);
                    JdbcExecUtil.execOne(sql, ds);
                }
            } else {
                // 数据表中索引名不存在，则新增索引
                String sql = iIndex.add(tableMeta.getClazz(), indexInfo);
                JdbcExecUtil.execOne(sql, ds);
            }
        }
    }

    /**
     * 获取索引更新脚本列表
     *
     * @param dbType
     * @param tableMeta
     */
    public static List<String> getUpdateSQL(DbType dbType, TableMeta tableMeta) {
        List<String> sqlList = new LinkedList<>();
        List<TableMetaIndexInfo> metaIndexInfos = tableMeta.getTableMeta().getIndexList();
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableIndexInfo> indexList = tableInfo.getIndexList();

        //处理库中索引数据
        Map<String, List<TableMetaIndexInfo>> indexMap = metaIndexInfos.stream().filter(e -> StringUtil.isNotBlank(e.getIndexName())).collect(Collectors.groupingBy(TableMetaIndexInfo::getIndexName));
        List<TableIndexInfo> metaList = new ArrayList<>();
        for (Map.Entry<String, List<TableMetaIndexInfo>> entry : indexMap.entrySet()) {
            List<TableMetaIndexInfo> valList = entry.getValue();
            Boolean nonUnique = valList.get(0).getNonUnique();
            TableIndexInfo info = new TableIndexInfo();
            info.setUnique(!nonUnique);
            info.setIndexName(valList.get(0).getIndexName());
            info.setColumns(valList.stream().map(e -> e.getColumnName().toLowerCase()).collect(Collectors.toList()));
            metaList.add(info);
        }

        IIndex iIndex = IndexFactory.getInstance(dbType);
        for (TableIndexInfo indexInfo : indexList) {
            List<String> columns = indexInfo.getColumns().stream().map(e -> e.toLowerCase()).collect(Collectors.toList());
            TableIndexInfo dbIndex = metaList.stream().filter(e -> e.getColumns().containsAll(columns) && columns.containsAll(e.getColumns())).findFirst().orElse(null);
            if (dbIndex != null) {
                // 数据表中索引名已经存在, 则修改索引
                if (dbIndex.isUnique() != indexInfo.isUnique()) {
                    String sql = iIndex.modify(tableMeta.getClazz(), indexInfo, dbIndex);
                    sqlList.add(sql);
                }
            } else {
                // 数据表中索引名不存在，则新增索引
                String sql = iIndex.add(tableMeta.getClazz(), indexInfo);
                sqlList.add(sql);
            }
        }

        return sqlList;
    }

}
